package com.skirmisher.inspection.common.timeTask;

import com.skirmisher.inspection.common.entity.InsLoop;
import com.skirmisher.inspection.common.mapper.InsLoopMapper;
import com.skirmisher.inspection.common.service.SystemCodeCacheService;
import com.skirmisher.inspection.common.sysenum.InsJobStatusEnum;
import com.skirmisher.inspection.conform.entity.*;
import com.skirmisher.inspection.conform.mapper.*;
import com.skirmisher.inspection.daily.entity.*;
import com.skirmisher.inspection.daily.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @ClassName InsTemp2JobTimeTask
 * @Description 定时任务 根据模板生成任务
 * @Author hanwangxin
 * @Date 2020/12/12 下午2:01
 * @Version 1.0
 */
@Slf4j
@Component
@Transactional
public class InsTemp2JobTimeTask {

    @Autowired
    private InsDailyTemplateMapper insDailyTemplateMapper;

    @Autowired
    private InsDaliyTemplateItemsMapper insDaliyTemplateItemsMapper;
    @Autowired
    private InsDaliyWorkerMapper insDaliyWorkerMapper;
    @Autowired
    private InsLoopMapper insLoopMapper;

    @Autowired
    private SystemCodeCacheService systemCodeCacheService;

    @Autowired
    private InsDaliyJobItemsMapper insDaliyJobItemsMapper;

    @Autowired
    private InsDaliyJobWorkerMapper insDaliyJobWorkerMapper;

    @Autowired
    private InsDailyJobMapper insDailyJobMapper;

    @Autowired
    private InsConformTemplateMapper insConformTemplateMapper;

    @Autowired
    private InsConformJobMapper insConformJobMapper;

    @Autowired
    private InsConformTemplateItemsMapper insConformTemplateItemsMapper ;

    @Autowired
    private InsConformWorkerMapper insConformWorkerMapper;

    @Autowired
    private InsConformJobWorkerMapper insConformJobWorkerMapper;

    @Autowired
    private InsConformJobItemsMapper insConformJobItemsMapper;



    @Scheduled(cron = "0/30 * * * * ? ")
    public void conformTemp2Job(){
        List<InsConformTemplate> insconformTempList = insConformTemplateMapper.listTempByTime();
        if (insconformTempList == null || insconformTempList.size()<=0){
            return;
        }
        log.info("符合巡查生成任务开始执行");
        for (InsConformTemplate insConformTemp : insconformTempList) {
            //处理时间参数
            List<Date> nextTime = new ArrayList<>();
            boolean flag = dealWithConformLoopTime(insConformTemp,nextTime);
            if (!flag){
                break;
            }

            String tempId = insConformTemp.getId();
            //封装job 实体
            InsConformJob job = new InsConformJob();
            dealWithComfromJob(insConformTemp, job);
            job.setInsPlanBeginTime(nextTime.get(0));
            //插入job
            insConformJobMapper.insert(job);
            //插入job的巡检项目
            List<InsConformTemplateItems> tempItems = insConformTemplateItemsMapper.getByTempId(tempId);
            if (tempItems != null && tempItems.size() > 0){
                for (InsConformTemplateItems conformTemplateItems : tempItems) {
                    InsConformJobItems jobItem = new InsConformJobItems();
                    BeanUtils.copyProperties(conformTemplateItems, jobItem);
                    jobItem.setItemId(UUID.randomUUID().toString());
                    jobItem.setTempId(job.getId());
                    insConformJobItemsMapper.insert(jobItem);

                }
            }

            //插入巡查人员
            List<InsConformWorker> tempWorkers = insConformWorkerMapper.getByBindId(tempId);
            if (tempWorkers !=null && tempWorkers.size() > 0){
                for (InsConformWorker tempWorker : tempWorkers) {
                    InsConformJobWorker jobWorker = new InsConformJobWorker();
                    BeanUtils.copyProperties(tempWorker, jobWorker);
                    jobWorker.setId(UUID.randomUUID().toString());
                    jobWorker.setBindId(job.getId());
                    jobWorker.setJobId(job.getId());

                    insConformJobWorkerMapper.insert(jobWorker);
                }
            }


        }


        log.info("符合巡查生成任务执行完毕");

    }

    /**
     * @Author hanwangxin
     * @Description //TODO 处理循环参数 * @Date 下午4:35 2020/12/12
     * @Param [insDailyTemplate]
     * @return boolean
     **/
    public boolean dealWithConformLoopTime(InsConformTemplate conformTemplate,List<Date> nextTime){

        String tempId = conformTemplate.getId();
        //获取循环列表
        List<InsLoop> byTempId = insLoopMapper.getByTempId(tempId);
        Date nextExecuteTime = conformTemplate.getNextExecuteTime();

        //更新模板的下次执行时间
        LocalDateTime checkTime = null;
        boolean returnFlage = true;
        if (nextExecuteTime == null){
            checkTime = LocalDateTime.now();
            returnFlage = false;
        }else {
            checkTime = Instant.ofEpochMilli(nextExecuteTime.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
            returnFlage = true;
            nextTime.add(nextExecuteTime);
        }
        LocalDateTime nextWorkTime = findNextExeuteTime(byTempId, checkTime);
        InsConformTemplate nextTimeTemp = new InsConformTemplate();
        nextTimeTemp.setId(conformTemplate.getId());
        nextTimeTemp.setNextExecuteTime(Date.from(nextWorkTime.atZone(ZoneId.systemDefault()).toInstant()));
        insConformTemplateMapper.updateIgnoreNull(nextTimeTemp);

        return returnFlage;
    }

    /**
     * @Author hanwangxin
     * @Description //TODO 将模板参数封装为任务 * @Date 下午2:21 2020/12/12
     * @Param []
     * @return void
     **/
    public void dealWithComfromJob(InsConformTemplate insConformTemplate, InsConformJob job){

        if (insConformTemplate != null){
            BeanUtils.copyProperties(insConformTemplate, job);
            String jobId = UUID.randomUUID().toString();
            job.setId(jobId);
            job.setTempId(insConformTemplate.getId());
            String jobCode = systemCodeCacheService.getNextCode(SystemCodeCacheService.CONFORMJOB);
            job.setJobName(insConformTemplate.getTempName()+"-"+jobCode);

            job.setJobCode(jobCode);
            job.setJobDesc(insConformTemplate.getTempDesc());
            job.setJobStatus(InsJobStatusEnum.READY2WORK.getStatus()+"");
            job.setRecTime(new Date());
            job.setRecCode("admin");
            job.setRecName("系统管理员");
        }
    }


    @Scheduled(cron = "0/30 * * * * ? ")
    public void daliyDaliyTemp2Job(){

        //获取需要生成任务的模板
        List<InsDailyTemplate> insDailyTemplates = insDailyTemplateMapper.listTempByTime();
        if (insDailyTemplates == null || insDailyTemplates.size()<=0){
            return;
        }

        //循环模板生成任务
        log.info("日常巡查生成任务开始执行");
        for (InsDailyTemplate insDailyTemplate : insDailyTemplates) {
            //处理时间参数
            List<Date> nextTime = new ArrayList<>();
            boolean flag = dealWithLoopTime(insDailyTemplate,nextTime);
            if (!flag){
                break;
            }

            String tempId = insDailyTemplate.getId();
            //封装job 实体
            InsDailyJob job = new InsDailyJob();
            dealWithJob(insDailyTemplate, job);
            job.setInsPlanBeginTime(nextTime.get(0));
            //插入job
            insDailyJobMapper.insert(job);
            //插入job的巡检项目
            List<InsDaliyTemplateItems> tempItems = insDaliyTemplateItemsMapper.getByTempId(tempId);
            if (tempItems != null && tempItems.size() > 0){
                for (InsDaliyTemplateItems insDaliyTemplateItems : tempItems) {
                    InsDaliyJobItems jobItem = new InsDaliyJobItems();
                    BeanUtils.copyProperties(insDaliyTemplateItems, jobItem);
                    jobItem.setItemId(UUID.randomUUID().toString());
                    jobItem.setTempId(job.getId());
                    insDaliyJobItemsMapper.insert(jobItem);

                }
            }

            //插入巡查人员
            List<InsDaliyWorker> tempWorkers = insDaliyWorkerMapper.getByBindId(tempId);
            if (tempWorkers !=null && tempWorkers.size() > 0){
                for (InsDaliyWorker tempWorker : tempWorkers) {
                    InsDaliyJobWorker jobWorker = new InsDaliyJobWorker();
                    BeanUtils.copyProperties(tempWorker, jobWorker);
                    jobWorker.setId(UUID.randomUUID().toString());
                    jobWorker.setBindId(job.getId());
                    jobWorker.setJobId(job.getId());

                    insDaliyJobWorkerMapper.insert(jobWorker);
                }
            }


        }


        log.info("日常巡查生成任务执行完毕");
    }

    /**
     * @Author hanwangxin
     * @Description //TODO 将模板参数封装为任务 * @Date 下午2:21 2020/12/12
     * @Param []
     * @return void
     **/
    public void dealWithJob(InsDailyTemplate insDailyTemplate,InsDailyJob job){

        if (insDailyTemplate != null){
            BeanUtils.copyProperties(insDailyTemplate, job);
            String jobId = UUID.randomUUID().toString();
            job.setId(jobId);
            job.setTempId(insDailyTemplate.getId());
            String jobCode = systemCodeCacheService.getNextCode(SystemCodeCacheService.DAILYJOB);
            job.setJobName(insDailyTemplate.getTempName()+"-"+jobCode);

            job.setJobCode(jobCode);
            job.setJobDesc(insDailyTemplate.getTempDesc());
            job.setJobStatus(InsJobStatusEnum.READY2WORK.getStatus()+"");
            job.setRecTime(new Date());
            job.setRecCode("admin");
            job.setRecName("系统管理员");
        }
    }

    /**
     * @Author hanwangxin
     * @Description //TODO 处理循环参数 * @Date 下午4:35 2020/12/12
     * @Param [insDailyTemplate]
     * @return boolean
     **/
    public boolean dealWithLoopTime(InsDailyTemplate insDailyTemplate,List<Date> nextTime){

        String tempId = insDailyTemplate.getId();
        //获取循环列表
        List<InsLoop> byTempId = insLoopMapper.getByTempId(tempId);
        Date nextExecuteTime = insDailyTemplate.getNextExecuteTime();

        //更新模板的下次执行时间
        LocalDateTime checkTime = null;
        boolean returnFlage = true;
        if (nextExecuteTime == null){
            checkTime = LocalDateTime.now();
            returnFlage = false;
        }else {
            checkTime = Instant.ofEpochMilli(nextExecuteTime.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
            returnFlage = true;
            nextTime.add(nextExecuteTime);
        }
        LocalDateTime nextWorkTime = findNextExeuteTime(byTempId, checkTime);
        InsDailyTemplate nextTimeTemp = new InsDailyTemplate();
        nextTimeTemp.setId(insDailyTemplate.getId());
        nextTimeTemp.setNextExecuteTime(Date.from(nextWorkTime.atZone(ZoneId.systemDefault()).toInstant()));
        insDailyTemplateMapper.updateIgnoreNull(nextTimeTemp);

        return returnFlage;
    }

    /**
     * @Author hanwangxin
     * @Description //TODO 寻找到指定LocalDateTime下次的执行时间 * @Date 下午4:35 2020/12/12
     * @Param [tempLoops, checkTime]
     * @return java.time.LocalDateTime
     **/
    public LocalDateTime findNextExeuteTime(List<InsLoop> tempLoops,LocalDateTime checkTime){
        //获取当前时间的月数 星期数

        int dayOfMonth = checkTime.getDayOfMonth();
        int weekDay = checkTime.getDayOfWeek().getValue();
        int year = checkTime.getYear();
        int month = checkTime.getMonth().getValue();
        int checkHour = checkTime.getHour();

        //新建后的第一次执行 找出循环列表中的日期 判断是否与小于当前日期
        LocalDateTime nextWorkTime = null;

        for (InsLoop insLoop : tempLoops) {
            String loopType = insLoop.getLoopType();
            LocalDateTime oneTime= null;//本次循环周期的最近一次执行时间
            if (loopType.equals("mon")){
                //按照月进行循环
                List<Integer> mon = insLoop.getMon();
                List<Integer> time = insLoop.getTime();
                //下次执行时间
                int nextMonday = mon.get(0);
                int nextTime = time.get(0);
                boolean isNextMon = true;
               for01: for (Integer monDay : mon) {
                    //找到第一个比当前日期大的天
                    if (monDay > dayOfMonth){
                        nextMonday = monDay;
                        isNextMon = false;
                        break;
                    }else if (monDay == dayOfMonth){
                        //同一天比较时间
                        nextMonday = monDay;
                        for02:for (Integer hour : time) {
                            if (hour > checkHour){
                                nextTime = hour;
                                isNextMon = false;
                                break for01;
                            }
                        }
                    }
                }
                //得出该此循环的下次执行时间
                if (nextTime == 24){
                    nextTime = 0;
                    nextMonday ++;
                }else if(month == 2 && nextMonday >= 29){
                    isNextMon = true;
                    month ++;
                    nextTime = time.get(0);
                }
                if (isNextMon){
                    if (month == 12){
                        oneTime = LocalDateTime.of(year+1,1,nextMonday,nextTime,0);
                    }else {
                        oneTime = LocalDateTime.of(year,month+1,nextMonday,nextTime,0);
                    }

                }else {
                    oneTime = LocalDateTime.of(year,month,nextMonday,nextTime,0);
                }

            }else {
                //按照周期进行循环
                List<Integer> weekList = insLoop.getWeek();
                List<Integer> time = insLoop.getTime();
                int nextTime = time.get(0);
                int weekTime = weekList.get(0);
                boolean isNextWeek = true;
                for01:for (Integer week : weekList) {
                    if (week > weekDay){
                        weekTime = week;
                        isNextWeek = false;
                        break;
                    }else if (week == weekDay){
                        //同一天比较时间
                        weekTime = week;
                        for02:for (Integer hour : time) {
                            if (hour > checkHour){
                                nextTime = hour;
                                isNextWeek = false;
                                break for01;
                            }
                        }
                    }
                }
                //构建下次执行时间
                int addDays = Math.abs(weekDay - weekTime);
                if (isNextWeek){
                    addDays += weekTime;
                }
                oneTime = LocalDateTime.of(year,month,dayOfMonth,nextTime,0).plusDays(addDays);
            }

            if (nextWorkTime == null){
                nextWorkTime = oneTime;
            }else{
                boolean before = nextWorkTime.isBefore(oneTime);
                if (!before){
                    nextWorkTime = oneTime;
                }
            }
        }

        return nextWorkTime;
    }

}
